import random
import threading
import traceback
from datetime import datetime
import pandas as pd
import time
import schedule
from DrissionPage import Chromium, ChromiumOptions, SessionOptions
from DrissionPage.common import Settings
from handle_asset_link import get_original_balance_budget, update_balance_budget, select_campaign_by_name
from loguru import logger
from read_search_file import get_complete_sheet1
from DrissionPage.common import Keys

lock = threading.Lock()
Settings.set_language("zh_cn")
co = ChromiumOptions(read_file=False)  # 不读取文件方式新建配置对象
so = SessionOptions(read_file=False)
browser = Chromium(addr_or_opts=co, session_options=so)

def log_message(log_callback, message, color=None):
    if callable(log_callback):
        log_callback(message, color) if color else log_callback(message)
def is_number(value):
    return type(value) in (int, float, complex)

def adjust_budget_for_accounts(df_sheet, adjustment, unit_dict_cookie, failed_records, log_callback=None):
    total_rows = len(df_sheet)
    adjustment = int(adjustment * 100)  # 假设 adjustment 是浮点数，需要乘以 100 转换为整数

    for index, dd in enumerate(df_sheet.itertuples()):
        try:
            log_message(log_callback, f'正在处理第 {index+1}/{total_rows} 条数据...', "purple")
            account_id = dd.子账户ID.strip() if pd.notna(dd.子账户ID) else ''
            account_name = dd.账户名.strip() if pd.notna(dd.账户名) else ''

            original_budget = get_original_balance_budget(cookies=unit_dict_cookie, account_id=account_id, log_callback=log_callback)
            log_message(log_callback, f'正在修改预算...修改子账号:【{account_name}】预算 {original_budget / 100} -> {(original_budget + adjustment) / 100}', "purple")
            logger.info(f'正在修改预算...修改子账号:【{account_name}】预算 {original_budget / 100} -> {(original_budget + adjustment) / 100}')
            update_balance_budget(cookies=unit_dict_cookie, account_id=account_id, budget=original_budget, adjustment=adjustment, log_callback=log_callback)

            time.sleep(random.randint(2, 3))
        except Exception as e:
            account_id = dd.子账户ID.strip() if pd.notna(dd.子账户ID) else ''
            account_name = dd.账户名.strip() if pd.notna(dd.账户名) else ''

            # 记录失败信息
            failed_records.append({'账户名': account_name, '子账号ID': account_id})
            error_msg = f"{type(e).__name__}: {str(e)}"
            error_trace = traceback.format_exc()
            logger.error(f"错误类型: {type(e).__name__}\n错误详情: {error_msg}\n堆栈跟踪:\n{error_trace}")
            # log_message(log_callback=log_callback, message=f'子账号ID预算修改失败:{account_id}, 查询当前子账户名称为【每日调整】的计划并进行状态的开启和关闭', color="purple")
            log_message(log_callback=log_callback, message=f'子账号ID预算修改失败:{account_id}, 继续执行下一条', color="purple")
            # select_campaign_by_name(cookies=unit_dict_cookie, account_id=account_id, log_callback=log_callback)
            time.sleep(random.randint(1, 3))
            continue

    log_message(log_callback, f'当前预算调整批次已完成', "blue")

def start_sub_account_url(file_path, adjustment, log_callback=None):
    df_sheet = get_complete_sheet1(file_path)
    first_account_id = df_sheet.iloc[0]['子账户ID']

    if '子账户ID' not in df_sheet.columns:
        log_message(log_callback, "表格中缺少子账户ID列", "red")
        return

    if '账户名' not in df_sheet.columns:
        log_message(log_callback, "表格中缺少账户名列", "red")
        return

    unit_dict_cookie = None
    # 初始化失败记录列表
    failed_records = []

    # 执行两次预算调整：第一次增加，第二次还原
    for i, adj in enumerate([adjustment, -adjustment]):
        log_message(log_callback, f'{f"增加预算阶段 :{adjustment}" if i == 0 else f"还原预算阶段:{-adjustment}"}', "blue")

        if i == 0:
            unit_dict_cookie = open_account_palt_form(first_account_id)

        adjust_budget_for_accounts(df_sheet, adj, unit_dict_cookie, failed_records, log_callback)
        time.sleep(5)  # 每次调整之间等待几秒


    # 如果有失败记录，生成Excel文件
    if failed_records:
        # 转换为DataFrame并去重
        failed_df = pd.DataFrame(failed_records)
        failed_df = failed_df.drop_duplicates(subset=['账户名', '子账号ID'])

        # 生成时间戳文件名
        timestamp = datetime.now().strftime("%m%d_%H%M")
        output_filename = f"预算修改失败数据汇总_{timestamp}.xlsx"

        try:
            failed_df.to_excel(output_filename, index=False)
            log_message(log_callback, f'已生成失败账户统计表: {output_filename}', "blue")
        except Exception as e:
            error_msg = f"生成失败账户统计表时出错: {str(e)}"
            logger.error(error_msg)
            log_message(log_callback, error_msg, "red")

    log_message(log_callback, f'全部数据处理完毕...', "orange")

def open_account_palt_form(account_id):
    account_tab = browser.new_tab('https://partner.xiaohongshu.com/partner/subAccount-list')

    account_tab.ele('tag:input@@class=el-input__inner@@type=text@@autocomplete=off@@placeholder=请输入').click(by_js=True)
    account_tab.ele('tag:input@@class=el-input__inner@@type=text@@autocomplete=off@@placeholder=请输入').input(account_id).input(Keys.ENTER)

    account_tab.wait(2)

    search_none_ele = account_tab.ele('tag:tr@@class=d-table__empty-row@@text()=暂无数据', timeout=0.5)
    if search_none_ele:
        return

    account_tab.ele('tag:span@@text():跳转', timeout=2).hover()
    jg_ele = account_tab.ele('tag:span@@class=d-text --color-static --color-current --size-text-paragraph d-text-nowrap d-text-ellipsis@@text():聚光平台', timeout=2)

    create_plan_tab = jg_ele.click.for_new_tab(by_js=True)
    create_plan_tab.wait.title_change("计划列表")
    unit_dict_cookie = create_plan_tab.cookies(all_info=False).as_dict()
    return unit_dict_cookie

def scheduled_task(file_path, adjustment):
    """定时任务执行函数"""
    print(f"开始执行定时任务: {datetime.now()}")
    start_sub_account_url(file_path, adjustment)
    print(f"定时任务执行完成: {datetime.now()}")

def run_scheduler(file_path, adjustment):
    """运行调度器"""
    # 设置每天下午6点执行
    schedule.every().day.at("18:00").do(scheduled_task, file_path, adjustment)
    
    print("定时任务已启动，每天下午6点执行预算调整")
    print(f"下次执行时间: {schedule.next_run()}")
    
    while True:
        schedule.run_pending()
        time.sleep(60)  # 每分钟检查一次

if __name__ == '__main__':
    file_path = r"D:\Users\Desktop\0722-智博(1).xlsx"
    adjustment = 0.1  # 预算调整值
    
    # 立即执行一次
    print("立即执行一次预算调整任务")
    start_sub_account_url(file_path, adjustment)
    
    # 启动定时任务
    run_scheduler(file_path, adjustment)